import time
from util import display,button,buttonDownLevel,beep

# button event detect
class BtnEvtDet:
	def __init__(self,holdTime=500,idleTime=3000):
		# init state
		self.S_INIT = 0
		self.S_CLICK = 1
		self.S_HOLD = 2
		self.state = self.S_INIT

		# time stamp
		self.clickTs = 0 
		self.initTs = time.ticks_ms()
		self.HOLD_TIME = holdTime
		self.IDLE_TIME = idleTime
	
	def detect(self):
		pinValue = button.value() # read
		if self.state == self.S_INIT: # init state
			if pinValue == buttonDownLevel: # down
				self.state = self.S_CLICK
				self.clickTs = time.ticks_ms()
				return 0 # idle
			else: # up
				if time.ticks_ms()-self.initTs >= self.IDLE_TIME:
					self.initTs = time.ticks_ms()
					return 5 # timeout
				else:
					return 0 # idle
		elif self.state == self.S_CLICK: # click state
			if pinValue == buttonDownLevel: # down
				# hold more than 300ms (default)
				if time.ticks_ms()-self.clickTs >= self.HOLD_TIME:
					self.state = self.S_HOLD
					return 2 # hold
			else:  # up
				self.state = self.S_INIT
				self.initTs = time.ticks_ms()
				return 1 # click
		elif self.state == self.S_HOLD:
			if pinValue == buttonDownLevel: # down
				return 3 # holding
			else:  # up
				self.state = self.S_INIT
				self.initTs = time.ticks_ms()
				return 4 # release

class Window:
	def __init__(self,sampleTime=150):
		self.componets = []
		self.comp_num = 0
		self.focusIndex = -1
		self.quit = False
		self.bed = BtnEvtDet()
		self.SAMPLE_TIME = sampleTime
		self.timeStamp = time.ticks_ms()

		self._cb_draw = None
		self._cb_idle = None
		self._cb_timeout = None
		self._cb_click = None
		self._cb_hold = None
		self._cb_holding = None
		self._cb_release = None
	
	def show(self):
		display.fill(0)
		if self._cb_draw != None:
			self._cb_draw()
		for c in self.componets:
			c.draw()
		display.show()
	
	# window callbacks
	def setDrawCB(self,draw):
		self._cb_draw = draw
	
	def setIdleCB(self,idle):
		self._cb_idle = idle

	def setTimeoutCB(self,timeout):
		self._cb_timeout = timeout
	
	def setClickCB(self,click):
		self._cb_click = click
	
	def setHoldCB(self,hold):
		self._cb_hold = hold

	def setHoldingCB(self,holding):
		self._cb_holding = holding

	def setReleaseCB(self,release):
		self._cb_release = release

	def add(self,c):
		self.componets.append(c)
		self.comp_num += 1
	
	# loop
	def run(self):
		self.quit = False
		while not self.quit:
			evt = self.bed.detect()
			self.handle(evt)
			self.show()
			dt = self.SAMPLE_TIME - (time.ticks_ms() - self.timeStamp) 
			if dt > 0:
				time.sleep_ms(dt)
			self.timeStamp = time.ticks_ms()
	
	def close(self):
		self.quit = True

	# handle event
	def handle(self,evt):
		if evt == 0 and self._cb_idle != None: #idle
			self._cb_idle()
		elif evt == 1: # click
			self._click()
			beep()
		elif evt ==2: # hold
			self._hold()
		elif evt ==3: # holding
			self._holding()
		elif evt ==4: # release
			self._release()
		elif evt ==5 and self._cb_timeout != None: # timeout
			self._cb_timeout()

	def _click(self): # switch focus
		if self.comp_num>0:
			if self.focusIndex == -1:
				self.focusIndex = 0
			else:
				self.componets[self.focusIndex].focus = 0 # lose focus
				self.focusIndex = (self.focusIndex + 1) % self.comp_num
			self.componets[self.focusIndex].focus = 1 # get focus
		if self._cb_click != None:
			self._cb_click()
	
	def _hold(self):
		if self.comp_num>0 and self.focusIndex!=-1:
			cb = self.componets[self.focusIndex].cb_hold
			if cb != None:
				cb()
		if self._cb_hold != None:
			self._cb_hold()

	def _holding(self):
		if self.comp_num>0 and self.focusIndex!=-1:
			cb = self.componets[self.focusIndex].cb_holding
			if cb != None:
				cb()
		if self._cb_holding != None:
			self._cb_holding()
	
	def _release(self):
		if self.comp_num>0 and self.focusIndex!=-1:
			cb = self.componets[self.focusIndex].cb_release
			if cb != None:
				cb()
		if self._cb_release != None:
			self._cb_release()
